<!---
	* Author: Cristian Costantini 
	* License: http://www.apache.org/licenses/LICENSE-2.0
	 --->
	 
<cfcomponent output="false">

	<cffunction name="init" access="public" returntype="EventManager" output="false" hint="Constructor">
		
		<cfset variables.eventListener = structNew() />
		
		<cfset configureEvent() />
		
		<cfreturn this />
	</cffunction>
	
	<cffunction name="notifyCacheRemoved" access="public" returntype="void">
		<cfargument name="class" type="String" required="true" />
		<cfset fireEvent( 'onCacheRemoved', arguments ) />
	</cffunction>
	
	<cffunction name="notifyCacheAdded" access="public" returntype="void">
		<cfargument name="class" type="String" required="true" />
		<cfset fireEvent( 'onCacheAdded', arguments ) />
	</cffunction>
	
	<cffunction name="notifyElementRemoved" access="public" returntype="void">
		<cfargument name="element" type="String" required="true" />
		<cfset fireEvent( 'onElementRemoved', arguments ) />
	</cffunction>
	
	<cffunction name="notifyElementPut" access="public" returntype="void">
		<cfargument name="element" type="String" required="true" />
		<cfset fireEvent( 'onElementPut', arguments ) />
	</cffunction>
	
	<cffunction name="notifyElementExpiry" access="public" returntype="void">
		<cfargument name="element" type="String" required="true" />
		<cfset fireEvent( 'onElementExpired', arguments ) />
	</cffunction>
	
	<cffunction name="notifyRemoveAll" access="public" returntype="void">
		<cfset fireEvent( 'onElementsRemoveAll' ) />
	</cffunction>
	
	<cffunction name="registerListener" access="public" returntype="void">
		<cfargument name="name" type="String" required="true" />
		<cfargument name="object" type="Any" required="true" />
		<cfargument name="async" type="boolean" required="true" />
		<cfset var listener = structNew() />
		
		<cfif not eventExists( arguments.name )>
			<cfabort showerror="Missing #arguments.name# event ! Please add an event to cfc" />
		</cfif>
		
		<cfset listener[ 'object' ] = arguments.object />
		<cfset listener[ 'async' ] = arguments.async />
		
		<cfset variables.eventListener[ arguments.name ].listeners.add( listener ) />
		
	</cffunction>
	
	<cffunction name="unregisterListener" access="public" returntype="void">
		<cfargument name="name" type="String" required="true" />
		<cfargument name="object" type="Any" required="true" />
		
		<cfset variables.eventListener[ arguments.name ].remove( arguments.object ) />
	</cffunction>

	<cffunction name="eventExists" access="public" returntype="boolean">
		<cfargument name="name" type="String" required="true" />
		<cfreturn structKeyExists( variables.eventListener, arguments.name ) />
	</cffunction>

	<!--- Utils --->
	
	<cffunction name="clearCounters" access="public" returntype="void">
		<cfset var i = "" />
		
		<cfloop collection="#variables.eventListener#" item="i">
			<cfset variables.eventListener[ i ].statistics = 0 />
		</cfloop>
		
	</cffunction>
	
	<!--- Private --->
	
	<cffunction name="configureEvent" access="private" returntype="void" output="false">
		<cfscript>
		addEvent( 'onCacheAdded' );
		addEvent( 'onCacheRemoved' );
		addEvent( 'onElementPut' );
		addEvent( 'onElementExpired' );
		addEvent( 'onElementRemoved' );
		addEvent( 'onElementsRemoveAll' );
		addEvent( 'onElementExpiry' );
		</cfscript>
	</cffunction>
	
	<cffunction name="addEvent" access="private" returntype="void">
		<cfargument name="name" type="String" required="true" hint="Event name" />
		<cfscript>
		if( not eventExists( arguments.name ) ){
		
			variables.eventListener[ arguments.name ] = structNew();
			variables.eventListener[ arguments.name ].listeners = arrayNew(1);
			variables.eventListener[ arguments.name ].statistics = 0;
		
		}
		</cfscript>
	</cffunction>
	
	<cffunction name="getCounter" access="private" returntype="Numeric">
		<cfargument name="name" type="String" required="true" />
		<cfreturn variables.eventListener[ arguments.name ].statistics />
	</cffunction>
	
	<cffunction name="incr" access="private" returntype="void" hint="Increment stats">
		<cfargument name="name" type="String" required="true" />
		<cfset var s = variables.eventListener[ arguments.name ].statistics />
		<cfset s = s + 1 />
	</cffunction>
	
	<cffunction name="fireEvent" access="private" returntype="void">
		<cfargument name="name" type="String" required="true" hint="Event name" />
		<cfargument name="args" type="Struct" required="false" default="#structNew()#" hint="Event name" />
		<cfset var listeners = variables.eventListener[arguments.name].listeners.iterator() />
		<cfset var listener = structNew() />
		
		<cfloop condition="#listeners.hasNext()#">
		
			<cfset listener = listeners.next() />
			
			<cfif listener.async >
				
				<cfthread name="#arguments.name#_#createUUID()#" action="run" component="#listener.object#" method="#arguments.name#" argumentcollection="#arguments.args#" >
			
					<cfinvoke component="#component#" method="#method#" argumentcollection="#argumentcollection#" />
			
				</cfthread>
				
			<cfelse>
			
				<cfinvoke component="#listener.object#" method="#arguments.name#" argumentcollection="#arguments.args#" />
			
			</cfif>
			
		</cfloop>
		
		<cfset incr( arguments.name ) />
		
	</cffunction>

</cfcomponent>